{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Backtest Example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 环境设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# -*- encoding: utf-8 -*-\n",
    "import time\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import statsmodels.api as sm\n",
    "from jaqs.data import DataApi\n",
    "\n",
    "from jaqs.data import RemoteDataService\n",
    "from jaqs.trade import AlphaBacktestInstance\n",
    "from jaqs.trade import PortfolioManager\n",
    "import matplotlib.pyplot as plt\n",
    "#from jaqs.trade import RealTimeTradeApi\n",
    "%matplotlib inline\n",
    "import jaqs.util as jutil\n",
    "import jaqs.trade.analyze as ana\n",
    "from jaqs.trade import AlphaStrategy\n",
    "from jaqs.trade import AlphaTradeApi\n",
    "from jaqs.trade import model\n",
    "from jaqs.data import DataView"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Begin: DataApi login 17321165656@tcp://data.quantos.org:8910\n",
      "    login success \n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'0,'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 设置文件存储路径\n",
    "dataview_dir_path = '../output/backtest/dataview'\n",
    "backtest_result_dir_path = 'backtest'\n",
    "backtest_result_folder = '../output/backtest'\n",
    "# 设置服务器地址、用户名密码\n",
    "# 例如：\n",
    "# data_config = {\n",
    "#   \"remote.data.address\": \"tcp://data.quantos.org:8910\",\n",
    "#   \"remote.data.username\":  '18688888888',\n",
    "#   \"remote.data.password\":  '23sdjfk209d0fs9dejkl2j3k4j9d0fsdf'}\n",
    "\n",
    "# 如果没有使用quantos金融终端，请自行替换phone,token内容\n",
    "import os\n",
    "phone = os.environ.get(\"QUANTOS_USER\")\n",
    "token = os.environ.get(\"QUANTOS_TOKEN\")\n",
    "\n",
    "data_config = {\n",
    "  \"remote.data.address\": \"tcp://data.quantos.org:8910\",\n",
    "  \"remote.data.username\":  phone,\n",
    "  \"remote.data.password\":  token}\n",
    "trade_config = {\n",
    "  \"remote.trade.address\": \"tcp://gw.quantos.org:8901\",\n",
    "  \"remote.trade.username\":  phone,\n",
    "  \"remote.trade.password\":  token}\n",
    "# RemoteDataService communicates with a remote server to fetch data\n",
    "ds = RemoteDataService()\n",
    "# Use username and password in data_config to login\n",
    "ds.init_from_config(data_config)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 设置参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "UNIVERSE = '000300.SH'\n",
    "START_DATE = 20151207\n",
    "END_DATE = 20180531"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 准备DataView"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Initialize config success.\n",
      "Query data...\n",
      "Query data - query...\n",
      "NOTE: price adjust method is [post adjust]\n",
      "238\n",
      "477\n",
      "238\n",
      "477\n",
      "46\n",
      "93\n",
      "140\n",
      "187\n",
      "234\n",
      "281\n",
      "328\n",
      "375\n",
      "422\n",
      "469\n",
      "516\n",
      "563\n",
      "610\n",
      "WARNING: some data is unavailable: \n",
      "    At fields \n",
      "Query data - daily fields prepared.\n",
      "Query instrument info...\n",
      "Query adj_factor...\n",
      "Query benchmark...\n",
      "Query benchmar member info...\n",
      "Query groups (industry)...\n",
      "Data has been successfully prepared.\n"
     ]
    }
   ],
   "source": [
    "dataview_props = {# Start and end date of back-test\n",
    "                  'start_date': START_DATE, 'end_date': END_DATE,\n",
    "                  # Investment universe and performance benchmark\n",
    "                  'universe': UNIVERSE, 'benchmark': UNIVERSE,\n",
    "                  # Data fields that we need\n",
    "                  'fields': 'pe_ttm,total_mv,sw1',\n",
    "                  # freq = 1 means we use daily data. Please do not change this.\n",
    "                  'freq': 1}\n",
    "\n",
    "# DataView utilizes RemoteDataService to get various data and store them\n",
    "dv = DataView()\n",
    "dv.init_from_config(dataview_props, ds)\n",
    "dv.prepare_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "industry = dv.get_ts('sw1')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "matching = {\n",
    "    '110000':'NLMY',\n",
    "    '210000':'Digging',\n",
    "    '220000':'Chemistry',\n",
    "    '230000':'Metal',\n",
    "    '240000':'Nonferrous Metal',\n",
    "    '270000':'Electronic&IT',\n",
    "    '280000':'Car',\n",
    "    '330000':'Appliance',\n",
    "    '340000':'Food',\n",
    "    '350000':'Clothing',\n",
    "    '360000':'Light Industrials',\n",
    "    '370000':'Health Care',\n",
    "    '410000':'Utility',\n",
    "    '420000':'Transportation',\n",
    "    '430000':'Housing',\n",
    "    '450000':'Commercial',\n",
    "    '460000':'Service',\n",
    "    '480000':'Bank',\n",
    "    '490000':'Non bank',\n",
    "    '510000':'Others',\n",
    "    '610000':'Construction Material',\n",
    "    '620000':'Construction decoration',\n",
    "    '630000':'Electronic equipment',\n",
    "    '640000':'Mechenical equipment',\n",
    "    '650000':'Army',\n",
    "    '710000':'Electronic&IT',\n",
    "    '720000':'Media',\n",
    "    '730000':'Telecom',\n",
    "    'nan': 'Unclassified'\n",
    "     }\n",
    "\n",
    "for key, value in matching.items():\n",
    "    industry = industry.replace(key, value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def group_sum(df, group_daily):\n",
    "    groups = np.unique(group_daily.values.flatten())\n",
    "    mask = groups == 'nan'\n",
    "    groups = groups[np.logical_not(mask)]\n",
    "    res = pd.DataFrame(index=df.index, columns=groups, data=np.nan)\n",
    "    for g in groups:\n",
    "        mask = group_daily == g\n",
    "        tmp = df[mask]\n",
    "        res.loc[:, g] = tmp.sum(axis=1)\n",
    "    return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "groups = ['0','nan','1']\n",
    "mask = groups == 'nan'\n",
    "np.logical_not(mask)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "total_mv = dv.get_ts('total_mv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "total_mv_industry = group_sum(total_mv, industry)\n",
    "weight_industry = total_mv_industry.div(total_mv_industry.sum(axis = 1), axis = 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 给定某一日期打印指数成份股总市值的行业分布"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Bank                       0.256074\n",
      "Non bank                   0.127831\n",
      "Digging                    0.074983\n",
      "Electronic&IT              0.043884\n",
      "Utility                    0.043800\n",
      "Housing                    0.043121\n",
      "Construction decoration    0.042441\n",
      "Transportation             0.040842\n",
      "Media                      0.037435\n",
      "Health Care                0.035701\n",
      "Car                        0.035267\n",
      "Chemistry                  0.034411\n",
      "Food                       0.029313\n",
      "Mechenical equipment       0.023761\n",
      "Nonferrous Metal           0.023391\n",
      "Army                       0.019155\n",
      "Electronic equipment       0.015127\n",
      "Appliance                  0.013135\n",
      "Metal                      0.012484\n",
      "Telecom                    0.012411\n",
      "Commercial                 0.011461\n",
      "NLMY                       0.006176\n",
      "Clothing                   0.005745\n",
      "Service                    0.004544\n",
      "Construction Material      0.004372\n",
      "Others                     0.002600\n",
      "Light Industrials          0.000535\n",
      "Name: 20151207, dtype: float64\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1bc94ef0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "TARGET_DATE = 20151207\n",
    "plt.figure(figsize = (16,8))\n",
    "weight_industry.loc[TARGET_DATE].sort_values(ascending = False).plot.bar()\n",
    "print(weight_industry.loc[TARGET_DATE].sort_values(ascending = False))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 回测"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 中性化函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cs_neutralize(input_array, size_array):\n",
    "    \n",
    "    var_Y = input_array.copy()\n",
    "    var_size = size_array.copy()\n",
    "    \n",
    "    var_X = var_size\n",
    "    var_X.columns = ['size']\n",
    "    var_X_const = sm.add_constant(var_X)\n",
    "\n",
    "    regressPanel = pd.concat([var_Y, var_X_const], axis = 1)\n",
    "    regressPanel = regressPanel.dropna()\n",
    "    var_Y = regressPanel.iloc[:, 0]\n",
    "    var_X = regressPanel.iloc[:, 1:3]    \n",
    "\n",
    "    # OLS regression\n",
    "    regressmodel = sm.OLS(var_Y, var_X)\n",
    "    results = regressmodel.fit()\n",
    "    return results.resid    \n",
    "\n",
    "def group_demean_regress(dv, signal, group, new_name, is_quarterly = False):\n",
    "    \n",
    "    df_goal   = dv.get_ts(signal)\n",
    "    df_output = df_goal.copy()\n",
    "    \n",
    "    industry = dv.get_ts(group)\n",
    "    log_tot_mv = np.log(dv.get_ts('total_mv'))\n",
    "\n",
    "    for i in range(len(df_output)):\n",
    "        df_output.iloc[i, :] = cs_neutralize(df_goal.iloc[i, :], log_tot_mv.iloc[i, :])\n",
    "\n",
    "    # insert into dv\n",
    "    dv.remove_field(new_name)\n",
    "    dv.append_df(df_output, new_name, is_quarterly = is_quarterly)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Field name [pe_ttm_size] does not exist. Stop remove_field.\n"
     ]
    }
   ],
   "source": [
    "group_demean_regress(dv, 'pe_ttm', 'sw1', 'pe_ttm_size', is_quarterly = False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Field [pct_pe] is overwritten.\n",
      "Field [gpct_pe] is overwritten.\n"
     ]
    }
   ],
   "source": [
    "# 在全指数中排序\n",
    "dv.add_formula('pct_pe', 'Percentile(pe_ttm)', is_quarterly = False)\n",
    "# 在行业内排序（行业中性化）\n",
    "dv.add_formula('gpct_pe', 'GroupPercentile(pe_ttm, sw1)', is_quarterly = False)\n",
    "# 将pe市值中性化后在全指数中排序（市值中性化）\n",
    "dv.add_formula('pct_pe_norm', 'Percentile(pe_ttm_size)', is_quarterly = False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 策略1： 选择指数成份股中pe最低10%的股票"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def select_func1(context, user_options=None):\n",
    "    snap = context.snapshot\n",
    "    score = snap[['pe_ttm', 'pct_pe', 'gpct_pe']]\n",
    "\n",
    "    score = score[score['pe_ttm'] >= 5]\n",
    "    score = score[score['pct_pe'] <= 0.1]\n",
    "    res = pd.merge(left=snap[['pe_ttm']], right=score[['pct_pe']], how='left', left_index=True, right_index=True)\n",
    "    res['pct_pe'] = ~res['pct_pe'].isnull()\n",
    "    res = res[['pct_pe']]\n",
    "\n",
    "#     show_selected(res)\n",
    "\n",
    "    context.storage['res'] = res\n",
    "#     print(res)\n",
    "    \n",
    "\n",
    "    return res"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 策略2： 选择行业中pe最低10%的股票（行业中性化）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def select_func2(context, user_options=None):\n",
    "    snap = context.snapshot\n",
    "    score = snap[['pe_ttm', 'pct_pe', 'gpct_pe']]\n",
    "\n",
    "    score = score[score['pe_ttm'] >= 5]\n",
    "    score = score[score['gpct_pe'] <= 0.1]\n",
    "    res = pd.merge(left=snap[['pe_ttm']], right=score[['pct_pe']], how='left', left_index=True, right_index=True)\n",
    "    res['pct_pe'] = ~res['pct_pe'].isnull()\n",
    "    res = res[['pct_pe']]\n",
    "\n",
    "#     show_selected(res)\n",
    "\n",
    "    context.storage['res'] = res\n",
    "#     print(res)\n",
    "    \n",
    "\n",
    "    return res"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 策略3： 将pe进行市值中性化处理后选最低10%的股票"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "def select_func3(context, user_options=None):\n",
    "    snap = context.snapshot\n",
    "    score = snap[['pe_ttm', 'pct_pe', 'gpct_pe', 'pct_pe_norm']]\n",
    "\n",
    "    score = score[score['pe_ttm'] >= 5]\n",
    "    score = score[score['pct_pe_norm'] <= 0.1]\n",
    "    res = pd.merge(left=snap[['pe_ttm']], right=score[['pct_pe']], how='left', left_index=True, right_index=True)\n",
    "    res['pct_pe'] = ~res['pct_pe'].isnull()\n",
    "    res = res[['pct_pe']]\n",
    "\n",
    "#     show_selected(res)\n",
    "\n",
    "    context.storage['res'] = res\n",
    "#     print(res)\n",
    "    \n",
    "\n",
    "    return res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AlphaStrategy Initialized.\n",
      "Run alpha backtest from 20151207 to 20180531\n",
      "=======new day 20151208\n",
      "Before 20151208 re-balance: available cash all = 1.0000e+08\n",
      "=======new day 20151215\n",
      "Before 20151215 re-balance: available cash all = 1.0239e+08\n",
      "=======new day 20151222\n",
      "Before 20151222 re-balance: available cash all = 1.0670e+08\n",
      "=======new day 20151229\n",
      "Before 20151229 re-balance: available cash all = 1.0365e+08\n",
      "=======new day 20160106\n",
      "Before 20160106 re-balance: available cash all = 9.6038e+07\n",
      "=======new day 20160113\n",
      "Before 20160113 re-balance: available cash all = 8.8431e+07\n",
      "=======new day 20160120\n",
      "Before 20160120 re-balance: available cash all = 8.7166e+07\n",
      "=======new day 20160127\n",
      "Before 20160127 re-balance: available cash all = 8.2564e+07\n",
      "=======new day 20160203\n",
      "Before 20160203 re-balance: available cash all = 8.2241e+07\n",
      "=======new day 20160217\n",
      "Before 20160217 re-balance: available cash all = 8.4540e+07\n",
      "=======new day 20160224\n",
      "Before 20160224 re-balance: available cash all = 8.5355e+07\n",
      "=======new day 20160302\n",
      "Before 20160302 re-balance: available cash all = 8.5769e+07\n",
      "=======new day 20160309\n",
      "Before 20160309 re-balance: available cash all = 8.4955e+07\n",
      "=======new day 20160316\n",
      "Before 20160316 re-balance: available cash all = 8.5305e+07\n",
      "=======new day 20160323\n",
      "Before 20160323 re-balance: available cash all = 9.2955e+07\n",
      "=======new day 20160330\n",
      "Before 20160330 re-balance: available cash all = 9.2967e+07\n",
      "=======new day 20160407\n",
      "Before 20160407 re-balance: available cash all = 9.3675e+07\n",
      "=======new day 20160414\n",
      "Before 20160414 re-balance: available cash all = 9.5142e+07\n",
      "=======new day 20160421\n",
      "Before 20160421 re-balance: available cash all = 9.0369e+07\n",
      "=======new day 20160428\n",
      "Before 20160428 re-balance: available cash all = 9.0021e+07\n",
      "=======new day 20160506\n",
      "Before 20160506 re-balance: available cash all = 9.0742e+07\n",
      "=======new day 20160513\n",
      "Before 20160513 re-balance: available cash all = 8.8586e+07\n",
      "=======new day 20160520\n",
      "Before 20160520 re-balance: available cash all = 8.7366e+07\n",
      "=======new day 20160527\n",
      "Before 20160527 re-balance: available cash all = 8.6915e+07\n",
      "=======new day 20160603\n",
      "Before 20160603 re-balance: available cash all = 9.1790e+07\n",
      "=======new day 20160614\n",
      "Before 20160614 re-balance: available cash all = 8.8495e+07\n",
      "=======new day 20160621\n",
      "Before 20160621 re-balance: available cash all = 9.0076e+07\n",
      "=======new day 20160628\n",
      "Before 20160628 re-balance: available cash all = 9.1911e+07\n",
      "=======new day 20160705\n",
      "Before 20160705 re-balance: available cash all = 9.5223e+07\n",
      "=======new day 20160712\n",
      "Before 20160712 re-balance: available cash all = 9.7352e+07\n",
      "=======new day 20160719\n",
      "Before 20160719 re-balance: available cash all = 9.7016e+07\n",
      "=======new day 20160726\n",
      "Before 20160726 re-balance: available cash all = 9.7379e+07\n",
      "=======new day 20160802\n",
      "Before 20160802 re-balance: available cash all = 9.7153e+07\n",
      "=======new day 20160809\n",
      "Before 20160809 re-balance: available cash all = 1.0145e+08\n",
      "=======new day 20160816\n",
      "Before 20160816 re-balance: available cash all = 1.0667e+08\n",
      "=======new day 20160823\n",
      "Before 20160823 re-balance: available cash all = 1.0487e+08\n",
      "=======new day 20160830\n",
      "Before 20160830 re-balance: available cash all = 1.0436e+08\n",
      "=======new day 20160906\n",
      "Before 20160906 re-balance: available cash all = 1.0548e+08\n",
      "=======new day 20160913\n",
      "Before 20160913 re-balance: available cash all = 1.0279e+08\n",
      "=======new day 20160922\n",
      "Before 20160922 re-balance: available cash all = 1.0324e+08\n",
      "=======new day 20160929\n",
      "Before 20160929 re-balance: available cash all = 1.0081e+08\n",
      "=======new day 20161013\n",
      "Before 20161013 re-balance: available cash all = 1.0391e+08\n",
      "=======new day 20161020\n",
      "Before 20161020 re-balance: available cash all = 1.0487e+08\n",
      "=======new day 20161027\n",
      "Before 20161027 re-balance: available cash all = 1.0508e+08\n",
      "=======new day 20161103\n",
      "Before 20161103 re-balance: available cash all = 1.0529e+08\n",
      "=======new day 20161110\n",
      "Before 20161110 re-balance: available cash all = 1.0633e+08\n",
      "=======new day 20161117\n",
      "Before 20161117 re-balance: available cash all = 1.0817e+08\n",
      "=======new day 20161124\n",
      "Before 20161124 re-balance: available cash all = 1.1168e+08\n",
      "=======new day 20161201\n",
      "Before 20161201 re-balance: available cash all = 1.1539e+08\n",
      "=======new day 20161208\n",
      "Before 20161208 re-balance: available cash all = 1.1343e+08\n",
      "=======new day 20161215\n",
      "Before 20161215 re-balance: available cash all = 1.1291e+08\n",
      "=======new day 20161222\n",
      "Before 20161222 re-balance: available cash all = 1.1366e+08\n",
      "=======new day 20161229\n",
      "Before 20161229 re-balance: available cash all = 1.1250e+08\n",
      "=======new day 20170106\n",
      "Before 20170106 re-balance: available cash all = 1.1243e+08\n",
      "=======new day 20170113\n",
      "Before 20170113 re-balance: available cash all = 1.1023e+08\n",
      "=======new day 20170120\n",
      "Before 20170120 re-balance: available cash all = 1.1240e+08\n",
      "=======new day 20170203\n",
      "Before 20170203 re-balance: available cash all = 1.1305e+08\n",
      "=======new day 20170210\n",
      "Before 20170210 re-balance: available cash all = 1.1392e+08\n",
      "=======new day 20170217\n",
      "Before 20170217 re-balance: available cash all = 1.1425e+08\n",
      "=======new day 20170224\n",
      "Before 20170224 re-balance: available cash all = 1.1564e+08\n",
      "=======new day 20170303\n",
      "Before 20170303 re-balance: available cash all = 1.1539e+08\n",
      "=======new day 20170310\n",
      "Before 20170310 re-balance: available cash all = 1.1555e+08\n",
      "=======new day 20170317\n",
      "Before 20170317 re-balance: available cash all = 1.1730e+08\n",
      "=======new day 20170324\n",
      "Before 20170324 re-balance: available cash all = 1.1962e+08\n",
      "=======new day 20170331\n",
      "Before 20170331 re-balance: available cash all = 1.1661e+08\n",
      "=======new day 20170411\n",
      "Before 20170411 re-balance: available cash all = 1.2367e+08\n",
      "=======new day 20170418\n",
      "Before 20170418 re-balance: available cash all = 1.2074e+08\n",
      "=======new day 20170425\n",
      "Before 20170425 re-balance: available cash all = 1.1873e+08\n",
      "=======new day 20170503\n",
      "Before 20170503 re-balance: available cash all = 1.1688e+08\n",
      "=======new day 20170510\n",
      "Before 20170510 re-balance: available cash all = 1.1269e+08\n",
      "=======new day 20170517\n",
      "Before 20170517 re-balance: available cash all = 1.1465e+08\n",
      "=======new day 20170524\n",
      "Before 20170524 re-balance: available cash all = 1.1172e+08\n",
      "=======new day 20170602\n",
      "Before 20170602 re-balance: available cash all = 1.1254e+08\n",
      "=======new day 20170609\n",
      "Before 20170609 re-balance: available cash all = 1.1588e+08\n",
      "=======new day 20170616\n",
      "Before 20170616 re-balance: available cash all = 1.1573e+08\n",
      "=======new day 20170623\n",
      "Before 20170623 re-balance: available cash all = 1.1743e+08\n",
      "=======new day 20170630\n",
      "Before 20170630 re-balance: available cash all = 1.1914e+08\n",
      "=======new day 20170707\n",
      "Before 20170707 re-balance: available cash all = 1.1932e+08\n",
      "=======new day 20170714\n",
      "Before 20170714 re-balance: available cash all = 1.1891e+08\n",
      "=======new day 20170721\n",
      "Before 20170721 re-balance: available cash all = 1.2178e+08\n",
      "=======new day 20170728\n",
      "Before 20170728 re-balance: available cash all = 1.2316e+08\n",
      "=======new day 20170804\n",
      "Before 20170804 re-balance: available cash all = 1.2197e+08\n",
      "=======new day 20170811\n",
      "Before 20170811 re-balance: available cash all = 1.1947e+08\n",
      "=======new day 20170818\n",
      "Before 20170818 re-balance: available cash all = 1.2338e+08\n",
      "=======new day 20170825\n",
      "Before 20170825 re-balance: available cash all = 1.2399e+08\n",
      "=======new day 20170901\n",
      "Before 20170901 re-balance: available cash all = 1.2509e+08\n",
      "=======new day 20170908\n",
      "Before 20170908 re-balance: available cash all = 1.2521e+08\n",
      "=======new day 20170915\n",
      "Before 20170915 re-balance: available cash all = 1.2594e+08\n",
      "=======new day 20170922\n",
      "Before 20170922 re-balance: available cash all = 1.2425e+08\n",
      "=======new day 20170929\n",
      "Before 20170929 re-balance: available cash all = 1.2235e+08\n",
      "=======new day 20171013\n",
      "Before 20171013 re-balance: available cash all = 1.2431e+08\n",
      "=======new day 20171020\n",
      "Before 20171020 re-balance: available cash all = 1.2275e+08\n",
      "=======new day 20171027\n",
      "Before 20171027 re-balance: available cash all = 1.2385e+08\n",
      "=======new day 20171103\n",
      "Before 20171103 re-balance: available cash all = 1.2143e+08\n",
      "=======new day 20171110\n",
      "Before 20171110 re-balance: available cash all = 1.2246e+08\n",
      "=======new day 20171117\n",
      "Before 20171117 re-balance: available cash all = 1.2342e+08\n",
      "=======new day 20171124\n",
      "Before 20171124 re-balance: available cash all = 1.2460e+08\n",
      "=======new day 20171201\n",
      "Before 20171201 re-balance: available cash all = 1.2416e+08\n",
      "=======new day 20171208\n",
      "Before 20171208 re-balance: available cash all = 1.2290e+08\n",
      "=======new day 20171215\n",
      "Before 20171215 re-balance: available cash all = 1.2034e+08\n",
      "=======new day 20171222\n",
      "Before 20171222 re-balance: available cash all = 1.1854e+08\n",
      "=======new day 20171229\n",
      "Before 20171229 re-balance: available cash all = 1.2099e+08\n",
      "=======new day 20180108\n",
      "Before 20180108 re-balance: available cash all = 1.2875e+08\n",
      "=======new day 20180115\n",
      "Before 20180115 re-balance: available cash all = 1.2708e+08\n",
      "=======new day 20180122\n",
      "Before 20180122 re-balance: available cash all = 1.3377e+08\n",
      "=======new day 20180129\n",
      "Before 20180129 re-balance: available cash all = 1.3566e+08\n",
      "=======new day 20180205\n",
      "Before 20180205 re-balance: available cash all = 1.3395e+08\n",
      "=======new day 20180212\n",
      "Before 20180212 re-balance: available cash all = 1.2040e+08\n",
      "=======new day 20180226\n",
      "Before 20180226 re-balance: available cash all = 1.2535e+08\n",
      "=======new day 20180305\n",
      "Before 20180305 re-balance: available cash all = 1.2299e+08\n",
      "=======new day 20180312\n",
      "Before 20180312 re-balance: available cash all = 1.2547e+08\n",
      "=======new day 20180319\n",
      "Before 20180319 re-balance: available cash all = 1.2232e+08\n",
      "=======new day 20180326\n",
      "Before 20180326 re-balance: available cash all = 1.1630e+08\n",
      "=======new day 20180402\n",
      "Before 20180402 re-balance: available cash all = 1.1848e+08\n",
      "=======new day 20180411\n",
      "Before 20180411 re-balance: available cash all = 1.1859e+08\n",
      "=======new day 20180418\n",
      "Before 20180418 re-balance: available cash all = 1.1550e+08\n",
      "=======new day 20180425\n",
      "Before 20180425 re-balance: available cash all = 1.1512e+08\n",
      "=======new day 20180504\n",
      "Before 20180504 re-balance: available cash all = 1.1366e+08\n",
      "=======new day 20180511\n",
      "Before 20180511 re-balance: available cash all = 1.1474e+08\n",
      "=======new day 20180518\n",
      "Before 20180518 re-balance: available cash all = 1.1647e+08\n",
      "=======new day 20180525\n",
      "Before 20180525 re-balance: available cash all = 1.1307e+08\n",
      "Backtest done. 646 days, 2.66e+03 trades in total. used time: 18.317663s\n",
      "Backtest results has been successfully saved to:\n",
      "C:\\Users\\lli\\AppData\\Roaming\\QuantosFinanceTerminal\\workspace\\__lectures\\output\\backtest\n",
      "process trades...\n",
      "get daily stats...\n",
      "calc strategy return...\n",
      "calc re-balance position\n",
      "Get stats\n",
      "Plot strategy PnL...\n",
      "generate report...\n",
      "HTML report: C:\\Users\\lli\\AppData\\Roaming\\QuantosFinanceTerminal\\workspace\\__lectures\\output\\backtest\\report.html\n"
     ]
    }
   ],
   "source": [
    "backtest_props = {# start and end date of back-test\n",
    "                  \"start_date\": START_DATE,\n",
    "                  \"end_date\": END_DATE,\n",
    "                  # re-balance period length\n",
    "                  \"period\": \"day\",\n",
    "                  \"n_periods\": 5,\n",
    "                  # benchmark and universe\n",
    "                  \"benchmark\": UNIVERSE,\n",
    "                  \"universe\": UNIVERSE,\n",
    "                  # Amount of money at the start of back-test\n",
    "                  \"init_balance\": 1e8,\n",
    "                  # Amount of money at the start of back-test\n",
    "                  \"position_ratio\": 1.0,\n",
    "                  \"commission_rate\": 15e-4,\n",
    "                  }\n",
    "backtest_props.update(data_config)\n",
    "\n",
    "my_selector = model.StockSelector()\n",
    "my_selector.add_filter('selector', select_func3)\n",
    "\n",
    "# We use trade_api to send orders\n",
    "trade_api = AlphaTradeApi()\n",
    "# This is our strategy\n",
    "strategy = AlphaStrategy(stock_selector=my_selector,\n",
    "                         pc_method='index_weight')\n",
    "# PortfolioManager helps us to manage tasks, orders and calculate positions\n",
    "pm = PortfolioManager()\n",
    "# BacktestInstance is in charge of running the back-test\n",
    "bt = AlphaBacktestInstance()\n",
    "\n",
    "# Public variables are stored in context. We can also store anything in it\n",
    "context = model.Context(dataview=dv, instance=bt, strategy=strategy, trade_api=trade_api, pm=pm)\n",
    "my_selector.register_context(context)\n",
    "#signal_model.register_context(context)\n",
    "\n",
    "bt.init_from_config(backtest_props)\n",
    "bt.run_alpha()\n",
    "\n",
    "# After finishing back-test, we save trade results into a folder\n",
    "bt.save_results(folder_path=backtest_result_folder)\n",
    "\n",
    "# Analyzer help us calculate various trade statistics according to trade results.\n",
    "# All the calculation results will be stored as its members.\n",
    "ta = ana.AlphaAnalyzer()\n",
    "\n",
    "ta.initialize(dataview=dv,\n",
    "              file_folder=backtest_result_folder)\n",
    "\n",
    "ta.do_analyze(result_dir=backtest_result_folder,\n",
    "              selected_sec=[])\n",
    "\n",
    "### 注：看报告的两种方法：（1）在本地运行，则直接打开html文件即可。 （2）在服务器上： 文件在：notebook/output/dataview2017之下，点开后，将路径中的”edit\"替换为“files\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py38",
   "language": "python",
   "name": "base"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
